﻿namespace LiveLabs.Logging.Logs
{
    using System;
    using System.IO;
    using System.Text;
    using Moq;
    using Xunit;
    using Xunit.Extensions;

    public class TextWriterLogFixture
    {
        private class TrackingTextWriter : TextWriter
        {
            public bool disposed = false;

            public override Encoding Encoding
            {
                get { return Encoding.UTF8; }
            }

            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
                this.disposed = true;
            }
        }

        [Fact]
        public void Should_Not_Dispose_Of_Writer_By_Default()
        {
            TrackingTextWriter mock = new TrackingTextWriter();

            using (TextWriterLog log = new TextWriterLog(mock))
            {
                // do nothing
            }

            Assert.False(mock.disposed);
        }

        [Fact]
        public void Should_Dispose_Of_Writer_When_Owns_Writer()
        {
            TrackingTextWriter mock = new TrackingTextWriter();

            using (TextWriterLog log = new TextWriterLog(mock, TextWriterResponsibility.Owns))
            {
                // do nothing
            }

            Assert.True(mock.disposed);
        }

        [Theory]
        [InlineData(typeof(OutOfMemoryException))]
        [InlineData(typeof(StackOverflowException))]
        // can't test thread abort exception as the constructors aren't available
        //[InlineData(typeof(ThreadAbortException))]
        public void Should_Pass_Through_Important_Exceptions(Type exType)
        {
            var mockWriter = new Mock<TextWriter>();
            mockWriter.Expect(x => x.WriteLine(It.IsAny<string>())).Throws(Activator.CreateInstance(exType, "msg") as Exception).Verifiable();
            mockWriter.Expect(x => x.Flush()).Never();

            TextWriterLog log = new TextWriterLog(mockWriter.Object, TextWriterResponsibility.DoesNotOwn);
            Assert.Throws(exType, () => log.WriteLine("hello world", LogLevel.Fatal));
 
            mockWriter.Verify();
        }

        [Fact]
        public void Should_Eat_Non_Important_Exceptions()
        {
            var mockWriter = new Mock<TextWriter>();
            mockWriter.Expect(x => x.WriteLine(It.IsAny<string>())).Throws<ArgumentNullException>().Verifiable();

            TextWriterLog log = new TextWriterLog(mockWriter.Object, TextWriterResponsibility.DoesNotOwn);
            Assert.DoesNotThrow(() => log.WriteLine("hello world", LogLevel.Fatal));

            mockWriter.Verify();
        }
    }
}
